#ifndef __CZF_TEXT_DOC_H__
#define __CZF_TEXT_DOC_H__


#include "vararryt.h"
#include "TextLine.h"
#include "EditStack.h"

typedef CTextLine*  PtrTextLine;
typedef CVarArrayT<PtrTextLine> CVarLines;

#define DOC_INIT_LINES 10
#define DOC_GROW_STEP 10


/*  CTextDoc derives from a vararray of CTextLine.
 *   Each CTextLine object represents a line of text, which is null terminated and \r or \n 
 *    or their combination is stripped. Because CR and LF are implied by a CTextLine object.
 *   Using row and col are 0 based.
 */

#define LAST_LINE (unsigned int)(-1)

class CTextSelection;

/* 
 * On return 0, no move is needed.
 * On return 1, the insert postion is returned in *line and *col
 */
int GetBlockMoveInsertPos(unsigned int* line, unsigned int* col, CTextSelection* sel);

class IBkPtMgr
{
public:
   virtual void ToggleBreakPoint (unsigned int lineno) = 0;
   virtual bool IsBreakPoint (unsigned int lineno) = 0;
   virtual void AdjustBreakPoints (bool insert, unsigned int lineno) = 0;
   virtual void ClearAllBreakPoints() = 0;
};

class CTextDoc : public CVarLines
{
public:
    CTextDoc ();
    virtual ~CTextDoc();

    int InsertTextAt (unsigned int row, unsigned int col, char* text,
		                       unsigned int* newrow=NULL, unsigned int* newcol=NULL);
    int InsertTextAtByStack (unsigned int row, unsigned int col, char* text);

    char* GetLineText(unsigned int row);
    int RemoveText (unsigned int rowStart, unsigned colStart, 
                             unsigned int rowEnd, unsigned int colEnd);
    void RemoveTextByStack (unsigned int rowStart, unsigned colStart, 
                             unsigned int rowEnd, unsigned int colEnd);
    void RemoveLeadingSpacesBefore(unsigned int row, unsigned int idx);

    void SetCrLf(const char* crlf);
    void SetStack(CEditStack* stack);
    void SetBkPtMgr(IBkPtMgr* mgr);

    size_t GetTextLength (unsigned int rowStart, unsigned colStart, 
                             unsigned rowEnd, unsigned int colEnd);
    size_t GetText (unsigned int rowStart, unsigned colStart, 
                             unsigned rowEnd, unsigned int colEnd, char* buf, size_t size);
    void ReadFile(const char* filename);
    void WriteFile(const char* filename);

    unsigned int GetMaxLineLength();
    CTextLine* GetLineObject(unsigned int line);

    /*  If str is found in sel_org, returns true, Otherwise returns false.
     *  If found, sel_found is updated to the found str position, 
     *  Please Note:
     *    Selection is  [smaller position, bigger position) 
     */
    bool FindInSelectionForward (CTextSelection* sel_org, const char* str,  CTextSelection* sel_found);
    
    /*  If str is found in sel_org, returns true, Otherwise returns false.
     *  If found, sel_found is updated to the found str position.
     *  Searchs from bigger position to smaller position.
     *  Please Note:
     *    Selection is  [smaller position, bigger position) 
     */
    bool FindInSelectionBackward (CTextSelection* sel_org, const char* str,  CTextSelection* sel_found);
    void SetDirty(bool dirty=true);
    bool IsDirty();
    void CloseDoc();

protected:    
    int InsertOneLineAfter (unsigned int row);
    void RemoveTextInLine(unsigned int r, unsigned int from, unsigned int to);
    int InsertTextHelper (unsigned int row, unsigned int col, char* text,
		                       unsigned int* newrow=NULL, unsigned int* newcol=NULL);
    void RemoveTextHelper(unsigned int rowStart, unsigned colStart, 
                             unsigned int rowEnd, unsigned int colEnd);
    bool m_dirty;
    CEditStack* m_stack;
    IBkPtMgr* m_pBkPtMgr;

public:
    /* The CVarArray::m_nCount is the total size of m_pArray,
     *  while m_nValidLines is the number of used elements of m_pArray;
     */
    unsigned int m_nValidLines;

public:
    char m_crlf[3];
};

/* StripCrLf strip 0x0a, 0x0d, 0x0a0d and 0x0d0a from "text" by setting those chars to null.
 *  After calling StripCrLf, "text" can be used directly for the first line of text.
 *  Using *nexttext as input for following call until *nexttext is NULL.
 */
void StripCrLf (char* text, char** nexttext);

/* Returns -1 if (r1,c1) is prior to (r2,c2);
 * 0, if (r1,c1) is the same as (r2, c2);
 * 1, if (r1,c1) is after (r2, c2);
 */
int CompareTextPosition (unsigned int r1, unsigned int c1, unsigned int r2, unsigned int c2);

/* Selection is  [smaller position, bigger position) */
 
class CTextSelection
{
public:
    CTextSelection ();
    virtual ~CTextSelection() {};

    bool InSelection (unsigned int line, unsigned int col);
    bool Selected ();
	void SetStart (unsigned int l, unsigned int c);
    void GetStart (unsigned int* l, unsigned int* c);
	void SetEnd (unsigned int l, unsigned int c);
    void GetEnd (unsigned int* l, unsigned int* c);
    void SetSelection (unsigned int l1, unsigned int c1, unsigned int l2, unsigned int c2); 
    void GetSelection (unsigned int* l1, unsigned int* c1, unsigned int* l2, unsigned int* c2); 
    /* returns true, if selected.*/
    bool GetAscendantInclusiveSel (unsigned int* sl, unsigned int* sc, unsigned int* bl, unsigned int* bc); 
    /* returns true, if selected.*/
    bool GetAscendantSel (unsigned int* sl, unsigned int* sc, unsigned int* bl, unsigned int* bc);
    /*
     * Return 0, if in selection; -1, if prior to selection; 1 if after selectrion
     */
    int ComparePosWithMe (unsigned int l, unsigned int c); 

protected:
    unsigned int m_nStartLine;
    unsigned int m_nStartCol;
    unsigned int m_nEndLine;
    unsigned int m_nEndCol;
};

typedef CVarArrayT<CTextSelection*> CVarSel;

#define SEL_INIT    10
#define SEL_GROW    10

class CSelections : public CVarSel
{
public:
    CSelections();
    virtual ~CSelections();

    /* returns the index of the this newly added sel on success.
     * returns -1 on error.
     */
    int AddSel(CTextSelection* sel);
    void RemoveAll();

public:
    unsigned int m_uSelCount;
};

#endif /* __CZF_TEXT_DOC_H__*/